Skip to content

Load typescript dynamically #702

Merged
RobinTail merged 15 commits intomake-v6from
dynamic-ts
Apr 11, 2026
Merged

Load typescript dynamically #702
RobinTail merged 15 commits intomake-v6from
dynamic-ts

Conversation

@RobinTail
Copy link
Copy Markdown
Owner

@RobinTail RobinTail commented Apr 11, 2026

This reduces memory usage

@RobinTail RobinTail added refactoring dependencies Pull requests that update a dependency file breaking labels Apr 11, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 11, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5a82fb28-4052-455f-8bb9-3d3b7269379c

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dynamic-ts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@RobinTail RobinTail changed the title Dynamic ts Load typescript dynamically Apr 11, 2026
Comment thread example/example-client.ts Outdated
@coveralls-official
Copy link
Copy Markdown

coveralls-official Bot commented Apr 11, 2026

Coverage Status

coverage: 99.04% (-1.0%) from 100.0% — dynamic-ts into make-v6

@RobinTail RobinTail added the documentation Improvements or additions to documentation label Apr 11, 2026
@RobinTail RobinTail marked this pull request as ready for review April 11, 2026 15:43
@RobinTail RobinTail mentioned this pull request Apr 11, 2026
@pullfrog
Copy link
Copy Markdown

pullfrog Bot commented Apr 11, 2026

TL;DR — Makes typescript an optional peer dependency by loading it dynamically instead of at module evaluation time. This reduces memory consumption for users who never generate client integrations, since the TypeScript compiler API is only imported when Integration is actually constructed.

Key changes

  • Introduce TypescriptAPI class wrapping the TypeScript compiler API — replaces the module-level import ts and free-standing helper functions with a lean instance that receives typescript via its constructor, making all TS factory calls instance methods.
  • Make typescript an optional peer dependency — adds peerDependenciesMeta marking it optional and changes all import ts to import type ts across production modules.
  • Add Integration.create() static async factory — provides a convenience method that dynamically import("typescript") so callers don't need to import it themselves.
  • Refactor Integration constructor to accept typescript parameter — the constructor now requires an explicit typescript property and stores identifiers as plain strings instead of pre-created AST nodes, deferring all node creation to the TypescriptAPI instance.
  • Thread api through ZTSContext for Zod-to-TS producers — every producer function now receives the TypescriptAPI instance via context instead of referencing module-level ts and f bindings.
  • Consolidate helpers into TypescriptAPImakeConst, makeInterface, makeTypeParams, makeId, and makeInterfaceProp are now first-class methods, removing duplication and unused properties (asyncModifier, accessModifiers).
  • Improve z.record() loose-mode representation — loose records now emit Record<K, V> & Record<PropertyKey, V> to accurately reflect that arbitrary keys are accepted.
  • Separate hasUndefined from isOptional in interface propsmakeInterfaceProp gains a hasUndefined parameter so z.exactOptional() can emit ? without adding | undefined.

Summary | 11 files | 15 commits | base: make-v6dynamic-ts


TypescriptAPI class replaces module-level TypeScript bindings

Before: typescript-api.ts exported free functions (ensureTypeNode, makeUnion, printNode, etc.) that captured ts and ts.factory at import time via a top-level import ts from "typescript".
After: A TypescriptAPI class receives the typescript module in its constructor and exposes all helpers as public instance methods. The top-level import is now import type ts — zero runtime cost.

The class encapsulates ts, f (factory), exportModifier, and the primitives list as instance state. Several helpers that Integration previously built inline (makeConst, makeInterface, makeTypeParams) are now first-class methods on TypescriptAPI. Previously exposed properties like asyncModifier and accessModifiers were removed as unused.

zod-sockets/src/typescript-api.ts · zod-sockets/src/zts-helpers.ts


typescript becomes an optional peer with dynamic import

Before: typescript was a required peer dependency — always loaded at startup regardless of usage.
After: Marked optional via peerDependenciesMeta. Users who only use Socket.IO runtime features and never call Integration no longer need it installed.

The new Integration.create() static async method calls await import("typescript") internally, while the constructor still accepts an explicit typescript parameter for synchronous / pre-loaded usage. The constructor's #ids record was simplified from pre-created AST nodes to plain strings — node creation is deferred to method calls.

API Import responsibility
new Integration({ typescript, ... }) Caller imports and passes typescript
await Integration.create({ ... }) Class dynamically imports it

zod-sockets/src/integration.ts · zod-sockets/package.json · CHANGELOG.md


Zod-to-TS producers receive api via context

Before: Producer functions in zts.ts accessed ts, f, and helpers like ensureTypeNode / makeUnion through module-level imports.
After: The ZTSContext interface gains an api: TypescriptAPI field. Every producer destructures { api } from context and calls methods on it.

This eliminates the runtime dependency on the top-level typescript import across the entire Zod-to-TS transformation pipeline. The onPrimitive factory switches from passing ts.SyntaxKind enum values directly to passing string literal keys (e.g. "StringKeyword") resolved at call time via api.ts.SyntaxKind. The samples lookup in onPipeline was moved inside the function body since it now depends on the api instance.

How does the loose record change work?

onRecord now checks def.mode === "loose" and, when true, wraps the output as Record<K, V> & Record<PropertyKey, V> using createIntersectionTypeNode. This accurately represents that a loose z.record() accepts keys beyond those explicitly enumerated.

zod-sockets/src/zts.ts · zod-sockets/src/zts-helpers.ts · zod-sockets/src/zts.spec.ts

Pullfrog  | View workflow run | Triggered by Pullfrog𝕏

Copy link
Copy Markdown

@pullfrog pullfrog Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clean refactor. The core idea — making typescript an injected dependency via the TypescriptAPI class — is well-executed. The create() static factory for dynamic import is a nice convenience alongside the explicit constructor. Two minor observations below.

Task list (7/7 completed)
  • Read full diff and identify major areas of change
  • Deep-dive into typescript-api.ts changes (largest file)
  • Review zts.ts changes (second largest)
  • Review integration.ts changes
  • Review package.json, helpers, tests, docs
  • Impact analysis for breaking changes
  • Submit review

Pullfrog  | Fix all ➔Fix 👍s ➔View workflow run𝕏

Comment thread zod-sockets/src/typescript-api.ts Outdated
Comment thread zod-sockets/src/zts.ts
@pullfrog
Copy link
Copy Markdown

pullfrog Bot commented Apr 11, 2026

No code changes needed — the author acknowledged the samples lazy-init suggestion but is okay with the current approach. Replied and resolved the thread.

Task list (3/3 completed)
  • Read and understand the review thread
  • Determine if any code changes are needed
  • Reply to the review comment and report progress

Pullfrog  | View workflow run | Triggered by Pullfrog𝕏

@pullfrog
Copy link
Copy Markdown

pullfrog Bot commented Apr 11, 2026

No action needed — both review threads are already addressed. The author removed the unused asyncModifier/accessModifiers (thread 1, now outdated) and acknowledged the samples allocation note (thread 2, already resolved).

Task list (3/3 completed)
  • Review all comment threads for actionable feedback
  • Determine if any code changes are needed
  • Report progress

Pullfrog  | View workflow run | Triggered by Pullfrog𝕏

@RobinTail RobinTail merged commit f86abd0 into make-v6 Apr 11, 2026
7 checks passed
@RobinTail RobinTail deleted the dynamic-ts branch April 11, 2026 16:18
@RobinTail RobinTail added this to the v6 milestone Apr 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

breaking dependencies Pull requests that update a dependency file documentation Improvements or additions to documentation refactoring

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant